﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class Error
{
    public string Message;
    public int Line;
}
namespace diamondc
{
    public class Varible
    {
        public string Name;
        public int Index;
        public bool array = false;
        public varTypes TYPE;
        public int Origin;
    }
    public enum varTypes
    {
        STRING = 1,
        INTEGER = 2,
        OBJECT = 3,
        BOOLEAN = 4,
    }
    public class Scope
    {
        public List<Varible> vars = new List<Varible>();
        public List<string> Instances = new List<string>();
        public string Name;

    }
    // The Diamond compiler , compilers diamond code into VIPER assembly language
    public class compiler
    {
        private IList<object> Tokens = new List<object>();
        private int Index = 0;
        public Object peekToken()
        {
            return Tokens[Index];
        }
        public Object peekToken(int i)
        {
            return Tokens[Index + i];
        }
        public Object readToken()
        {
            Index++;

            return Tokens[Index - 1];
        }
        public compiler(IList<object> tokens)
        {
            Tokens = tokens;

        }
        public List<Varible> getScopeVars()
        {
            List<Varible> final = new List<Varible>();
            foreach (Scope s in scope)
            {
                foreach (Varible v in s.vars)
                {
                    final.Add(v);
                }
            }
            return final;
        }
        public List<string> getScopeInstances()
        {
            List<string> final = new List<string>();
            foreach (Scope s in scope)
            {
                foreach (string v in s.Instances)
                {
                    final.Add(v);
                }
            }
            return final;
        }
        public string ILCode = "";
        string AssignType = "";
        List<import> imports = new List<import>();
        class import
        {
            public string name;
            public List<string> classes = new List<string>();
        }

        public List<string> references = new List<string>();
        public void addIL(string cmd)
        {
            ILCode += cmd + "\n";
        }
        public void ParseExpr()
        {
            string op = "";
            bool next = true;
            while (true)
            {
                if (isVarible())
                {
                    if (peekToken(1) == Scanner.OpenBracket)
                    {
                        foreach (Varible v in getScopeVars())
                        {
                            if (v.Name == peekToken().ToString())
                            {
                                readToken();
                                readToken();
                                if (!v.array)
                                {
                                    ParseExpr();

                                    addIL("ldptr " + v.Index.ToString());
                                    addIL("add");
                                    addIL("read");
                                    readToken();
                                }
                                else
                                {
                                    int index = (int)readToken();
                                    addIL("ldloc " + index + v.Origin);
                                    readToken();
                                }
                                break;
                            }
                        }
                    }
                    else
                    foreach (Varible v in getScopeVars())
                    {
                        if (v.Name == peekToken().ToString())
                        {
                            addIL("ldloc " + v.Index.ToString());
                            readToken();
                            break;
                        }
                    }
                }
                else if (peekToken() == Scanner.And)
                {
                    readToken();
                    foreach (Varible v in getScopeVars())
                    {
                        if (v.Name == peekToken().ToString())
                        {
                            addIL("ldptr " + v.Index.ToString());
                            readToken();
                            break;
                        }
                    }
                }
                else if (peekToken() is StringLiteral)
                {
                    StringLiteral sl = (StringLiteral)readToken();
                    addIL("push string '" + sl.Value + "'");
                }
                else if (peekToken().ToString() == "read")
                {
                    readToken();
                    readToken();
                    readToken();
                    addIL("sysf_inp");
                }
                else if (peekToken() is char)
                {
                    addIL("push byte " + ((byte)(char)readToken()).ToString());
                }
                    
                else if (peekToken().ToString() == "true")
                {
                    readToken();
                    addIL("push dword 1");
                }
                else if (peekToken().ToString() == "false")
                {
                    readToken();
                    addIL("push dword 0");
                }
                else if (isInstance() || peekToken().ToString() == "this")
                {
                    string instanceName = readToken().ToString();
                    if (readToken() == Scanner.Dot)
                    {
                        string fieldName = readToken().ToString();
                        addIL("get " + instanceName + "::" + fieldName);

                    }
                }
               
                else if (peekToken() is string)
                {
                    string name = readToken().ToString();
                    int vi = 0;
                    if (op != "")
                    {
                        addIL("stloc " + varIndex.ToString());
                        varIndex++;

                        vi = varIndex - 1;
                    }
                    if (peekToken() == Scanner.Dot)
                    {
                        readToken();
                        name += "::" + readToken().ToString();
                    }
                    Console.WriteLine(name);
                    PassParmeters();
                    addIL("call " + name.ToString());
                   
                    
                    if (op == "")
                    {
                    }
                    else
                    {
                        addIL("stloc " + varIndex.ToString());
                        varIndex++;
                        addIL("ldloc " + vi.ToString());
                        addIL("ldloc " + (varIndex - 1).ToString());
                        addIL("add");
                    }
                }
                else if (peekToken() is int)
                {
                    addIL("push dword " + readToken().ToString());
                }
                if(op != "")
                    addIL(op);

                if (peekToken() == Scanner.Add)
                {
                    op = "add";
                    readToken();
                }
                else if (peekToken() == Scanner.Sub)
                {
                    op = "sub";
                    readToken();
                }
                else if (peekToken() == Scanner.Div)
                {
                    op = "div";
                    readToken();
                }
                else if (peekToken() == Scanner.Mul)
                {
                    op = "mul";
                    readToken();
                }
                else
                {
                    break;
                }

            }
        }

        public object GetType()
        {

            foreach (Varible v in scope.Peek().vars)
            {
                if (v.Name == peekToken().ToString())
                {
                    if (v.TYPE == varTypes.STRING)
                    {
                        return "";
                    }
                    else if (v.TYPE == varTypes.INTEGER)
                    {
                        return (int)0;
                    }

                }
            }
            return "";
        }
        List<Varible> outVars = new List<Varible>();
        public string getLoop()
        {
            foreach (Scope s in scope)
            {
                if (s.Name == "for" || s.Name == "while" || s.Name == "times")
                {
                    string str = s.Name;
                    return str;
                }
            }
            
            return "none";
        }
        public void parseArgs()
        {
            if (peekToken() == Scanner.OpenPar)
            {
                readToken();
                if (peekToken() == Scanner.ClosePar)
                {
                    readToken();
                    return;
                }
                while (true)
                {
                    if (peekToken().ToString() == "string")
                    {
                        readToken();
                        string rs = readToken().ToString();
                        addIL("stloc " + varIndex);
                        Varible v = new Varible();
                        v.Index = varIndex;
                        v.Name = rs;
                        scope.Peek().vars.Add(v);
                        varIndex++;
                        addIL("pop");
                    }
                    else if (peekToken().ToString() == "char")
                    {
                        readToken();
                        string rs = readToken().ToString();
                        addIL("stloc " + varIndex);
                        Varible v = new Varible();
                        v.Index = varIndex;
                        v.Name = rs;
                        scope.Peek().vars.Add(v);
                        varIndex++;
                        addIL("pop");
                    }

                    else if (peekToken().ToString() == "var")
                    {
                        readToken();
                        string rs = readToken().ToString();
                        scope.Peek().Instances.Add(rs);
                        addIL("ldobj " + rs);
                        addIL("pop");
                    }
                    else if (peekToken().ToString() == "int")
                    {
                        readToken();
                        string rs = readToken().ToString();
                        addIL("stloc " + varIndex);
                        Varible v = new Varible();
                        v.Index = varIndex;
                        v.Name = rs;
                        scope.Peek().vars.Add(v);
                        varIndex++;
                        addIL("pop");
                    }
                    else if (peekToken().ToString() == "out")
                    {
                        readToken();
                        if (peekToken().ToString() == "string")
                        {
                            readToken();
                            string rs = readToken().ToString();
                            addIL("stloc " + varIndex);
                            Varible v = new Varible();
                            v.Index = varIndex;
                            v.Name = rs;
                            outVars.Add(v);
                            varIndex++;
                            v.Index = varIndex;
                            varIndex++;
                            scope.Peek().vars.Add(v);
                            addIL("pop");
                        }
                        else if (peekToken().ToString() == "int")
                        {
                            readToken();
                            string rs = readToken().ToString();
                            addIL("stloc " + varIndex);
                            Varible v = new Varible();
                            v.Index = varIndex;
                            v.Name = rs;
                            outVars.Add(v);
                            varIndex++;
                            v.Index = varIndex;
                            varIndex++;
                            scope.Peek().vars.Add(v);
                            addIL("pop");
                        }
                    }
                    else if (peekToken() == Scanner.Comma)
                    {
                        readToken();
                    }
                    else if (peekToken() == Scanner.ClosePar)
                    {

                        readToken();
                        Console.WriteLine(peekToken().ToString() + "E");
                        break;
                    }

                }
            }
        }
        Stack<int> timesScope = new Stack<int>();
        int varIndex = 0;
        Stack<Scope> scope = new Stack<Scope>();
        int currentVarIndex = 0;
        public void ParseBooleanExpr()
        {
            ParseExpr();
            addIL("stloc " + varIndex.ToString());
            
            int l1 = varIndex;
            varIndex++;
            if (peekToken() == Scanner.Equal)
            {
                readToken();
                ParseExpr();
                addIL("stloc " + varIndex.ToString());
                varIndex++;
                addIL("stloc " + varIndex.ToString());
                addIL("ldloc " + (varIndex - 1).ToString());
                addIL("ldloc " + (varIndex - 2).ToString());
                addIL("exnor");
                varIndex++;
            }
            else if (peekToken() == Scanner.NotEqual)
            {
                readToken();
                ParseExpr();
                addIL("stloc " + varIndex.ToString());
                varIndex++;
                addIL("stloc " + varIndex.ToString());
                addIL("ldloc " + (varIndex - 1).ToString());
                addIL("ldloc " + (varIndex - 2).ToString());
                addIL("exnor");
                addIL("not");
                
                varIndex++;
            }
            else if (peekToken() == Scanner.GreaterThan)
            {
                readToken();
                ParseExpr();
                addIL("stloc " + varIndex.ToString());
                varIndex++;
                addIL("stloc " + varIndex.ToString());
                addIL("ldloc " + (varIndex - 1).ToString());
                addIL("ldloc " + (varIndex - 2).ToString());
                addIL("cmpgt");

                varIndex++;
            }
            else if (peekToken() == Scanner.LessThen)
            {
                readToken();
                ParseExpr();
                addIL("stloc " + varIndex.ToString());
                varIndex++;
                addIL("stloc " + varIndex.ToString());
                addIL("ldloc " + (varIndex - 1).ToString());
                addIL("ldloc " + (varIndex - 2).ToString());
                addIL("cmplt");
                varIndex++;
            }
            else
            {
                addIL("ldloc " + l1);
                return;
            }
        }
        bool isVarible()
        {
            foreach (Scope s in scope)
            {
                foreach (Varible v in s.vars)
                {
                    if (peekToken().ToString() == v.Name)
                    {
                        currentVarIndex = v.Index;
                        return true;
                    }

                }

            }
            return false;
        }
        public void parseIntExpr()
        {
            while (true)
            {
                if (peekToken() is int)
                {
                    addIL("push dword " + peekToken().ToString());
                    readToken();
                    break;
                }
            }
        }
        bool isInstance()
        {
            if (peekToken().ToString() == "this")
            {
                return true;
            }
            foreach (string i in getScopeInstances())
            {
                if (peekToken().ToString() == i || peekToken().ToString() == "this")
                {
                    return true;
                }
            }
            return false;
        }

        public void PassParmeters()
        {
            if (readToken() == Scanner.OpenPar)
            {
                List<string> vars = new List<string>();
                while (true)
                {
                    if (peekToken().ToString() == "out")
                    {

                        readToken();
                        string vName = readToken().ToString();
                        foreach (Scope c in scope)
                        {
                            foreach (Varible v in c.vars)
                            {
                                if (v.Name == vName)
                                {
                                    addIL("push dword " + v.Index);
                                }
                            }
                        }

                    }
                    else if (isInstance())
                    {
                        addIL("push object " + readToken().ToString());
                    }
                    else
                    {
                        ParseExpr();
                        addIL("stloc " + varIndex.ToString());
                        vars.Add("ldloc " + varIndex.ToString());
                        varIndex++;
                    }
                    if (peekToken() == Scanner.Comma)
                    {
                        readToken();

                    }
                    else
                    {
                        break;
                    }

                }
                if (peekToken() == Scanner.ClosePar)
                {
                    readToken();
                }
                else
                {
                    throw new Exception("Expected )");
                }
                vars.Reverse();
                foreach (string s in vars)
                {
                    addIL(s);

                }
            }
            else
            {
                throw new Exception("Expected ( after " + peekToken().ToString());
            }
        }

        public List<Error> Errors = new List<Error>();
        public Stack<int> ifScope = new Stack<int>();
        int switchIndex = 0;
        Stack<int> switchScope = new Stack<int>();
        public void Error(string msg)
        {
            int id = 0;
            int Line = 0;
            foreach (List<int> i in Scanner.Lines)
            {
                foreach (int l in i)
                {
                    if (l == Index)
                    {
                        Line = id;
                        break;
                    }
                }
                id++;
            }
            Error e = new Error();
            e.Message = msg;
            e.Line = Line + 1;
            Errors.Add(e);
            Index = Scanner.Lines[Line + 1][0];
            compileMethod();
        }
        public int ifIndex = 0;
        public int whileIndex = 0;
        public Stack<int> whileScope = new Stack<int>();
        public Stack<string> forScope = new Stack<string>();
        public Stack<int> forEnds = new Stack<int>();
        int forIndex = 0;
        string method = "";
        public void compileMethod()
        {
            List<string> Imports = new List<string>();
            foreach (string s in references)
            {
                GEX lib = GEX.LoadFromFile(s);
                import imp = new import();
                foreach (GEXResource gr in lib.Files)
                {
                    imp.classes.Add(gr.Name.Replace(".bytecode", ""));
                    
                }
                imports.Add(imp);
                
            }

            while (true)
            {
                if (peekToken().ToString() == "print")
                {
                    readToken();
                    ParseExpr();
                    addIL("sysf_print");

                }
                else if (peekToken().ToString() == "if")
                {
                    readToken();
                    if (readToken() == Scanner.OpenPar)
                    {
                        addIL("; IF START");


                        ParseBooleanExpr();
                        addIL("push dword 1");
                        addIL("bne _if" + ifIndex.ToString());

                        Scope sc = new Scope();
                        sc.Name = "if";
                        scope.Push(sc);
                        ifScope.Push(ifIndex);

                        ifIndex++;
                        if (readToken() != Scanner.ClosePar)
                        {
                            throw new Exception("Expected )");
                        }

                    }
                    else
                    {
                        throw new Exception("Expected (");
                    }
                }
                else if (peekToken().ToString() == "import")
                {
                    
                }
                else if (peekToken().ToString() == "for")
                {
                    readToken();
                    Scope sc = new Scope();
                    sc.Name = "for";
                    scope.Push(sc);
                    int fv = 0;
                    if (readToken() == Scanner.OpenPar)
                    {
                        if (isVarible())
                        {
                            fv = (currentVarIndex);

                            readToken();
                        }
                        else
                        {
                            if (readToken().ToString() == "int")
                            {
                                Varible v = new Varible();
                                v.Index = varIndex;
                                v.Name = readToken().ToString();
                                fv = (varIndex);
                                varIndex++;
                                AssignType = "int";
                                scope.Peek().vars.Add(v);
                            }
                        }
                        forEnds.Push(forIndex);
                        forIndex++;
                        if (peekToken() == Scanner.Assign)
                        {
                            readToken();
                            ParseExpr();
                            addIL("stloc " + fv.ToString());

                            AssignType = "";
                        }
                        if (readToken() == Scanner.Comma)
                        {
                            addIL("._forstart" + forEnds.Peek().ToString());
                            ParseBooleanExpr();
                            addIL("push dword 1");
                            addIL("bne _for" + forEnds.Peek().ToString());
                            string end_code = "";
                            if (readToken() == Scanner.Comma)
                            {
                                if (isVarible())
                                {
                                    readToken();
                                    if (peekToken() == Scanner.Add)
                                    {
                                        readToken();
                                        if (peekToken() == Scanner.Add) //++
                                        {
                                            readToken();
                                            end_code += ("ldloc " + fv.ToString());
                                            end_code += ("\npush dword 1");
                                            end_code += ("\nadd");
                                            end_code += ("\nstloc " + fv.ToString());
                                        }
                                        else if (peekToken() == Scanner.Equal) // +=
                                        {
                                            readToken();
                                            ParseExpr();
                                            end_code += ("\nldloc " + fv.ToString());
                                            end_code += ("\nadd");
                                            end_code += ("\nstloc " + fv.ToString());
                                        }
                                        forScope.Push(end_code);
                                    }
                                    if (readToken() != Scanner.ClosePar)
                                    {
                                        throw new Exception("Expected )");
                                    }
                                }
                                else
                                {
                                    throw new Exception("Varible expected!");
                                }
                            }
                        }
                        else
                        {
                            throw new Exception("Expected ,");
                        }
                    }
                    else
                    {
                        throw new Exception("Expected (");
                    }
                }
                else if (peekToken().ToString() == "while")
                {
                    readToken();
                    if (readToken() == Scanner.OpenPar)
                    {
                        addIL("._whilestart" + whileIndex.ToString());
                        ParseBooleanExpr();
                        addIL("push dword 1");
                        Scope sc = new Scope();
                        sc.Name = "while";
                        scope.Push(sc);

                        addIL("bne _while" + whileIndex.ToString());
                        whileScope.Push(whileIndex);
                        whileIndex++;
                        if (readToken() != Scanner.ClosePar)
                        {
                            throw new Exception("Expected )");
                        }

                    }
                    else
                    {
                        throw new Exception("Expected (");
                    }
                }
                else if (peekToken(1) == Scanner.Colon)
                {
                    addIL("." + method + "_" + readToken().ToString());
                    readToken();
                }
                else if (peekToken().ToString() == "goto")
                {
                    readToken();
                    addIL("jmp " + method + "_" + readToken().ToString());
                }
                else if (peekToken().ToString() == "array")
                {
                    readToken();
                    string name = readToken().ToString();
                    Varible v = new Varible();
                    v.Origin = varIndex;
                    if (readToken() == Scanner.OpenBracket)
                    {
                        readToken();
                        int alloc = (int)readToken();
                        varIndex += alloc;
                        v.array = true;
                        scope.Peek().vars.Add(v);
                        if (readToken() != Scanner.CloseBracker)
                        {
                            throw new Exception("Expected [");
                        }
                    }
                    else
                    {
                        throw new Exception("Expected ]");
                    }
                }
                else if (peekToken().ToString() == "switch")
                {
                    readToken();
                    if (readToken() == Scanner.OpenPar)
                    {
                        ParseExpr();
                        addIL("stloc " + varIndex.ToString());

                        switchScope.Push(varIndex);
                        varIndex++;
                        Scope sc = new Scope();
                        sc.Name = "switch";
                        scope.Push(sc);
                        if (readToken() != Scanner.ClosePar)
                        {
                            throw new Exception("Expected )");
                        }
                    }
                    else
                    {
                        throw new Exception("Expected (");
                    }
                }
                else if (peekToken().ToString() == "case")
                {
                    addIL("._case" + switchIndex.ToString());
                    switchIndex++;
                    readToken();

                    ParseExpr();
                    if (readToken() != Scanner.Colon)
                    {
                        throw new Exception("Expected :");
                    }
                    addIL("ldloc " + switchScope.Peek().ToString());
                    addIL("bne _case" + switchIndex.ToString());
                }
                else if (peekToken().ToString() == "default")
                {
                    readToken();
                    if (readToken() != Scanner.Colon)
                    {
                        throw new Exception("Expected :");
                    }
                    addIL("._case" + switchIndex.ToString());
                    switchIndex++;
                }
                else if (peekToken().ToString() == "continue")
                {
                    readToken();
                    if (getLoop() != "none")
                    {
                        if (getLoop() == "for")
                        {
                            addIL(forScope.Peek());
                            addIL("jmp _forstart" + forEnds.Peek().ToString());
                        }
                        else if (getLoop() == "while")
                        {
                            addIL("jmp _whilestart" + whileScope.Peek().ToString());
                        }
                    }
                }
                else if (peekToken().ToString() == "break")
                {
                    readToken();
                    Stack<Scope> os = scope;
                    if (scope.Peek().Name == "switch")
                    {
                        addIL("jmp _endswitch" + switchScope.Peek().ToString());
                    }
                    else if (getLoop() != "none")
                    {
                        if (getLoop() == "for")
                        {
                            addIL("jmp _for" + forEnds.Peek().ToString());
                        }
                        else if (getLoop() == "while")
                        {
                            addIL("jmp _while" + whileScope.Peek().ToString());
                        }
                    }
                    scope = os;
                }

                else if (peekToken().ToString() == "times")
                {
                    readToken();

                    ParseExpr();
                    addIL("stloc " + varIndex.ToString());
                    addIL("push dword 0");
                    varIndex++;
                    addIL("stloc " + varIndex.ToString());
                    addIL("._times" + varIndex.ToString());
                    Scope sc = new Scope();
                    sc.Name = "times";
                    scope.Push(sc);
                    timesScope.Push(varIndex - 1);
                    varIndex++;
                }
                else if (peekToken().ToString() == "var")
                {
                    readToken();
                    string cname = readToken().ToString();
                    readToken();
                    if (readToken().ToString() == "new")
                    {
                        string baseClass = readToken().ToString();
                        addIL("newobj " + cname + "," + baseClass);
                        scope.Peek().Instances.Add(cname);
                        PassParmeters();
                        addIL("callinstance " + cname + "::.ctor");
                    }
                    else
                    {
                        throw new Exception("Expected new!");
                    }
                }
                else if (peekToken().ToString() == "end")
                {
                    readToken();
                    if (scope.Peek().Name == "times")
                    {
                        Console.WriteLine("SDS!!!!");
                        int timesindx = timesScope.Pop();
                        addIL("push dword 1");
                        addIL("ldloc " + (1 + timesindx).ToString());
                        addIL("add");
                        addIL("stloc " + (1 + timesindx).ToString());
                        addIL("ldloc " + timesindx.ToString());
                        addIL("ldloc " + (timesindx + 1).ToString());
                        addIL("bne _times" + (timesindx + 1).ToString());

                        scope.Pop();
                    }

                    else if (scope.Peek().Name == "if")
                    {
                        addIL("; WTF?");
                        addIL("._if" + ifScope.Pop().ToString());
                        scope.Pop();

                    }
                    else if (scope.Peek().Name == "while")
                    {
                        addIL("jmp _whilestart" + whileScope.Peek().ToString());
                        addIL("._while" + whileScope.Pop().ToString());
                        scope.Pop();

                    }
                    else if (scope.Peek().Name == "for")
                    {
                        addIL(forScope.Pop());
                        addIL("jmp _forstart" + forEnds.Peek().ToString());
                        addIL("._for" + forEnds.Peek().ToString());
                        scope.Pop();

                        forEnds.Pop();
                    }
                    else if (scope.Peek().Name == "switch")
                    {
                        addIL("._case" + switchIndex.ToString());
                        switchIndex++;
                        addIL("._endswitch" + switchScope.Pop().ToString());
                        scope.Pop();
                    }
                    else if (scope.Peek().Name == "proc")
                    {
                        foreach (Varible v in outVars)
                        {
                            addIL("ldloc " + (v.Index + 1).ToString());

                            addIL("ldloc " + v.Index.ToString());

                            addIL("stloc");
                        }
                        outVars = new List<Varible>();
                        scope.Pop();
                        goto endf;

                    }
                    else
                        break;
                }

                else if (peekToken().ToString() == "stop")
                {
                    readToken();
                    addIL("halt");
                }
                else if (peekToken() == Scanner.At)
                {
                    readToken();
                    if (isVarible())
                    {
                        readToken();
                        if (peekToken() == Scanner.Assign)
                        {
                            readToken();

                            ParseExpr();
                            addIL("ldloc " + currentVarIndex);
                            addIL("stptr");
                        }
                        else
                        {
                            throw new Exception("Expected =");
                        }


                    }
                }

                else if (isVarible())
                {
                    int i = currentVarIndex;
                    string n = readToken().ToString();
                    if (peekToken() == Scanner.OpenBracket)
                    {
                        readToken();
                        foreach (Varible v in getScopeVars())
                        {
                            if (v.Name == n)
                            {

                                ParseExpr();
                                readToken();
                                addIL("push dword " + v.Origin);
                                addIL("add");
                                addIL("stloc " + varIndex.ToString());
                                string s = "ldloc " + varIndex.ToString();
                                readToken();
                                if (peekToken() == Scanner.Assign)
                                {
                                    readToken();

                                    ParseExpr();
                                    addIL(s);

                                    addIL("stloc");
                                }
                                else
                                {
                                    throw new Exception("Expected =");
                                }
                            }

                        }
                    }
                    else if (peekToken() == Scanner.Assign)
                    {
                        readToken();

                        ParseExpr();
                        addIL("stloc " + i);
                    }
                    else
                    {
                        throw new Exception("Expected =");
                    }


                }

                else if (isInstance() && peekToken(3) == Scanner.Assign)
                {
                    string instanceName = readToken().ToString();
                    if (readToken() == Scanner.Dot)
                    {
                        string fieldName = readToken().ToString();
                        if (peekToken() == Scanner.Assign)
                        {
                            readToken();
                            ParseExpr();
                            addIL("set " + instanceName + "::" + fieldName);

                        }
                    }
                }
                else if (peekToken().ToString() == "string")
                {
                    readToken();
                    string sname = readToken().ToString();

                    if (peekToken() == Scanner.Assign)
                    {
                        readToken();
                        ParseExpr();
                        addIL("stloc " + varIndex.ToString());
                        Varible v = new Varible();
                        v.Name = sname;
                        v.Index = varIndex;
                        v.TYPE = varTypes.STRING;
                        scope.Peek().vars.Add(v);
                        varIndex++;
                    }
                }
                else if (peekToken().ToString() == "char")
                {
                    readToken();
                    string sname = readToken().ToString();

                    if (peekToken() == Scanner.Assign)
                    {
                        readToken();
                        ParseExpr();
                        addIL("stloc " + varIndex.ToString());
                        Varible v = new Varible();
                        v.Name = sname;
                        v.Index = varIndex;
                        v.TYPE = varTypes.STRING;
                        scope.Peek().vars.Add(v);
                        varIndex++;
                    }
                }
                else if (peekToken().ToString() == "return")
                {
                    readToken();
                    ParseExpr();
                    addIL("ret");
                }

                else if (peekToken().ToString() == "int")
                {
                    readToken();
                    string sname = readToken().ToString();

                    if (peekToken() == Scanner.Assign)
                    {
                        AssignType = "int";
                        readToken();
                        ParseExpr();
                        addIL("stloc " + varIndex.ToString());
                        Varible v = new Varible();
                        v.Name = sname;
                        v.Index = varIndex;
                        v.TYPE = varTypes.INTEGER;
                        AssignType = "";
                        scope.Peek().vars.Add(v);
                        varIndex++;
                    }
                }
                else if (peekToken().ToString() == "bool")
                {
                    readToken();
                    string sname = readToken().ToString();

                    if (peekToken() == Scanner.Assign)
                    {
                        readToken();
                        ParseBooleanExpr();
                        addIL("stloc " + varIndex.ToString());
                        Varible v = new Varible();
                        v.Name = sname;
                        v.Index = varIndex;
                        v.TYPE = varTypes.BOOLEAN;
                        scope.Peek().vars.Add(v);
                        varIndex++;
                    }
                }
                else if (isInstance())
                {
                    string name = readToken().ToString();
                    if (peekToken() == Scanner.Dot)
                    {
                        readToken();
                        name += "::" + readToken().ToString();
                    }
                    Console.WriteLine(name);
                    PassParmeters();
                    Console.WriteLine(peekToken().ToString() + "Is last.");
                    addIL("callinstance " + name.ToString());
                }
                else if (peekToken() is string)
                {
                    string name = readToken().ToString();
                    if (peekToken() == Scanner.Dot)
                    {
                        readToken();
                        name += "::" + readToken().ToString();
                    }
                    Console.WriteLine(name);
                    PassParmeters();
                    Console.WriteLine(peekToken().ToString() + "Is last.");
                    addIL("call " + name.ToString());


                }

            }
        endf:
            addIL("ret");
        }


        public void compile()
        {
            try
            {
                while (Index < Tokens.Count)
                {

                    if (peekToken().ToString() == "class")
                    {
                        readToken();
                        bool ctor = false;
                        string className = readToken().ToString();
                        if (peekToken().ToString() == "extends")
                        {
                            readToken();
                            className += ":" + readToken().ToString();
                        }
                        addIL("class " + className);
                        while (peekToken().ToString() != "end")
                        {
                            if (peekToken().ToString() == "string")
                            {
                                readToken();
                                string name = readToken().ToString();
                                addIL("declare " + name);
                            }
                            else if (peekToken().ToString() == "global")
                            {
                                addIL("global:");
                                readToken();
                            }
                            
                            else if (peekToken().ToString() == "void" || peekToken().ToString() == "function" || peekToken().ToString() == className)
                            {
                                if (peekToken().ToString() == className)
                                {
                                    readToken();
                                    addIL("proc .ctor");
                                    ctor = true;
                                }
                                else
                                {
                                    readToken();
                                    string name = readToken().ToString();
                                    method = name;
                                    if (name == "main" || name == "Main")
                                    {
                                        addIL("%entrypoint");
                                    }
                                    addIL("proc " + name);
                                }
                                Scope s = new Scope();
                                s.Name = "proc";
                                scope.Push(s);

                                parseArgs();
                                compileMethod();

                            }
                            else
                            {

                                Index++;
                            }

                        }
                        if (!ctor)
                        {
                            addIL("proc .ctor");
                            addIL("ret");
                        }
                        addIL("end class");
                    }

                    else
                    {
                        Index++;
                    }
                }
            }
            catch (Exception e)
            {
                Error(e.Message);
                return;
            }
        }



    }
}
